package com.idea.errorcode.messages.resolver;

import com.idea.errorcode.api.IErrorCode;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;

import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author: 沉香
 * @date: 2025/04/13
 * @description: 带缓存的国际化异常消息解析器
 */
public class CachedMessageResolver {

    // Spring MessageSource 实例（可选）
    private static MessageSource messageSource;

    // 原资源文件缓存结构
    private static final Map<String, Map<Locale, ResourceBundle>> BUNDLE_CACHE = new ConcurrentHashMap<>();
    private static final Map<String, String> MESSAGE_CACHE = new ConcurrentHashMap<>();

    // 区域设置管理
    private static volatile Locale defaultLocale = Locale.getDefault();

    private static final ThreadLocal<Locale> threadLocalLocale = new ThreadLocal<>();

    /**
     * 注入 Spring MessageSource（在Spring项目中调用）
     */
    public static void setMessageSource(MessageSource messageSource) {
        CachedMessageResolver.messageSource = messageSource;
    }

    /**
     * 设置全局默认语言
     */
    public static void setDefaultLocale(Locale locale) {
        defaultLocale = locale;
    }

    /**
     * 设置线程级语言
     */
    public static void setThreadLocalLocale(Locale locale) {
        threadLocalLocale.set(locale);
    }

    /**
     * 解析消息（自动选择最优方案）
     */
    public static String resolve(IErrorCode errorCode, Object... args) {
        Locale locale = Optional.ofNullable(threadLocalLocale.get())
                .orElse(defaultLocale);
        return resolveWithLocale(errorCode, locale, args);
    }

    /**
     * 指定语言解析
     */
    public static String resolveWithLocale(IErrorCode errorCode, Locale locale, Object... args) {
        // 优先使用 Spring MessageSource
        if (messageSource != null) {
            try {
                return messageSource.getMessage(
                        errorCode.getMessageKey(),
                        args,
                        formatDefaultMessage(errorCode, args),
                        locale
                );
            } catch (NoSuchMessageException e) {
                // 确保即使配置了MessageSource但key不存在时仍回退
                return formatDefaultMessage(errorCode, args);
            }
        }

        // 降级使用原资源文件方案
        return resolveWithResourceBundle(errorCode, locale, args);
    }

    /**
     * 原资源文件解析方案
     */
    private static String resolveWithResourceBundle(IErrorCode errorCode, Locale locale, Object... args) {
        final String baseName = "messages";
        try {
            ResourceBundle bundle = BUNDLE_CACHE
                    .computeIfAbsent(baseName, k -> new ConcurrentHashMap<>())
                    .computeIfAbsent(locale, l -> loadBundle(baseName, l));

            String template = getTemplateWithFallback(bundle, errorCode);
            return formatMessage(template, args);
        } catch (MissingResourceException e) {
            return formatDefaultMessage(errorCode, args);
        }
    }

    /**
     * 加载资源包
     */
    private static ResourceBundle loadBundle(String baseName, Locale locale) {
        return ResourceBundle.getBundle(baseName, locale);
    }

    /**
     * 获取模板（优先资源文件，不存在用默认消息）
     */
    private static String getTemplateWithFallback(ResourceBundle bundle, IErrorCode code) {
        return bundle.containsKey(code.getMessageKey()) ?
                bundle.getString(code.getMessageKey()) : code.getMessage();
    }

    /**
     * 格式化默认消息（无缓存）
     */
    private static String formatDefaultMessage(IErrorCode code, Object[] args) {
        return args != null && args.length > 0 ?
                MessageFormat.format(code.getMessage(), args) : code.getMessage();
    }

    /**
     * 带缓存的消息格式化
     */
    private static String formatMessage(String template, Object[] args) {
        if (args == null || args.length == 0) {
            return template;
        }

        String cacheKey = template + "|" + Arrays.hashCode(args);
        return MESSAGE_CACHE.computeIfAbsent(cacheKey,
                k -> MessageFormat.format(template, args));
    }

    /**
     * 清空缓存
     */
    public static void clearCache() {
        BUNDLE_CACHE.clear();
        MESSAGE_CACHE.clear();
    }
}